package wechat

import (
	"context"
	"fmt"
	"strings"

	"mall/common/globalkey"
	"mall/common/jwt"
	"mall/common/resultx"
	"mall/common/utils/pointy"
	"mall/service/forum/api/internal/lib/userrank"
	"mall/service/forum/api/internal/lib/usertask"
	"mall/service/forum/api/internal/svc"
	"mall/service/forum/api/internal/types"
	"mall/service/user/rpc/userclient"

	"github.com/sirupsen/logrus"
	"github.com/zeromicro/go-zero/core/logx"
)

type GetUserInfoLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewGetUserInfoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetUserInfoLogic {
	return &GetUserInfoLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *GetUserInfoLogic) GetUserInfo(req *types.UserInfoReq) (*types.CurrentUserInfo, error) { // Todo:
	userId := jwt.GetUserId(l.ctx)
	if userId == 0 {
		return nil, resultx.NewErrCode(resultx.TOKEN_EXPIRE_ERROR)
	}

	var authType *string
	if req.AuthType == nil || len(strings.TrimSpace(*req.AuthType)) == 0 {
		authType = pointy.GetPointer(globalkey.UserAuthTypeWechatMini)
	} else {
		authType = req.AuthType
	}

	res, err := l.svcCtx.UserRpc.GetUserInfo(l.ctx, &userclient.CurrentUserReq{
		AuthType: authType,
		UserId:   pointy.GetPointer(userId),
	})
	if err != nil {
		return nil, err
	}

	userProfile := res.UserProfile
	userAccount := res.UserAccount
	userRankList, err := l.getUserRankList(userId)
	var userRank *types.UserRankInfo
	var userNextRank *types.UserRankInfo
	var nextThreshold *int
	var nextCount uint32
	if err != nil {
		logrus.Info(fmt.Sprintf("GetUserInfo getUserRankList err: %+v", err))
	} else {
		var userLevel uint64
		if userProfile.Level != nil && *userProfile.Level > 0 {
			userLevel = uint64(*userProfile.Level)
		}
		var isNext int = 0
		for _, v := range userRankList {
			if isNext == 1 {
				userNextRank = v
				if len(v.Restrictions) > 0 {
					nextThreshold = pointy.GetPointer(len(v.Restrictions))
				}
				isNext = 0
				break
			}
			if v.Id != nil && *v.Id == userLevel {
				userRank = v
				isNext = 1
			}
		}
	}

	taskIdMap := make(map[uint64]string)
	userTaskList, err := l.getUserTaskList(userId)
	if err != nil {
		logrus.Info(fmt.Sprintf("GetUserInfo getUserRankList err: %+v", err))
	} else {
		for _, v := range userTaskList {
			if v.Id != nil && v.Slug != nil {
				taskIdMap[*v.Id] = *v.Slug
			}
		}
	}

	if userNextRank != nil {
		userRank.NextName = userNextRank.Name
		userRank.NextSlug = userNextRank.Slug
		if res.UserTaskStatisticMap != nil && len(userNextRank.Restrictions) > 0 {
			for _, v := range userNextRank.Restrictions {
				if v.TaskId != nil && *v.TaskId > 0 && v.Threshold != nil && *v.Threshold > 0 {
					if slug, ok := taskIdMap[*v.TaskId]; ok {
						if cnt, ok := res.UserTaskStatisticMap[slug]; ok {
							if cnt >= *v.Threshold {
								nextCount += 1
							}
						}
					}
				}
			}
		}
	}
	userRank.NextCount = nextCount
	if nextThreshold != nil {
		userRank.NextThreshold = pointy.GetPointer(uint32(*nextThreshold))
	}

	var birthdayHidden bool
	if userProfile.BirthdayHidden != nil && *userProfile.BirthdayHidden > 0 {
		birthdayHidden = true
	}

	return &types.CurrentUserInfo{
		UserProfile: &types.UserProfileInfo{
			Id:             userProfile.Id,
			Mobile:         userProfile.Mobile,
			Email:          userProfile.Email,
			Name:           userProfile.Name,
			Nickname:       userProfile.Nickname,
			Avatar:         userProfile.Avatar,
			Gender:         userProfile.Gender,
			Birthday:       userProfile.Birthday,
			BirthdayHidden: birthdayHidden,
			Info:           userProfile.Info,
		},
		UserAccount: &types.UserAccountInfo{
			Integral: userAccount.AvailablePoint,
			Growth:   userAccount.HistoryPoint,
			Gems:     userAccount.AvailableBalance,
			// RankId:    userAccount.Level,
		},
		UserRank: userRank,
	}, nil
}

func (l *GetUserInfoLogic) getUserRankList(userId uint64) (resp []*types.UserRankInfo, err error) {
	userRank := userrank.NewUserRank(l.ctx, l.svcCtx)

	return userRank.List(userId)
}

func (l *GetUserInfoLogic) getUserTaskList(userId uint64) (resp []*types.UserTaskInfo, err error) {
	userTask := usertask.NewUserTask(l.ctx, l.svcCtx)

	return userTask.List(userId)
}
